package com.exercise.rpc.server;/**
 * Created by kete on 2018-10-26.
 */

import com.exercise.rpc.common.model.RpcRequest;
import com.exercise.rpc.common.model.RpcResponse;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import net.sf.cglib.reflect.FastClass;
import net.sf.cglib.reflect.FastMethod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 作者：kete
 * 创建时间：2018-10-26 10:10
 * 功能描述：
 * 版本：
 */
public class ServiceHandler extends SimpleChannelInboundHandler<RpcRequest> {

    private final static Logger logger = LoggerFactory.getLogger(ServiceHandler.class);

    private Map<String,Object> handlerMap = new ConcurrentHashMap<>();

    public ServiceHandler(Map<String, Object> handlerMap) {
        this.handlerMap = handlerMap;
    }

    @Override
    protected void channelRead0(final ChannelHandlerContext ctx, final RpcRequest msg) throws Exception {
        RpcResponse rpcResponse = new RpcResponse();
        rpcResponse.setRequestId(msg.getRequestId());

        try {
            Object result = handler(msg);
            rpcResponse.setResult(result);
        } catch (Exception e) {
            logger.error("handle result failure", e);
            rpcResponse.setException(e);
        }

        ctx.writeAndFlush(rpcResponse).addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture channelFuture) throws Exception {
                logger.debug("Send response for request " + msg.getRequestId());
            }
        });

    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.error("server caught exception", cause);
        ctx.close();
    }

    private Object handler(RpcRequest request) throws Exception{
        String serviceName = request.getInterfaceName();
        String serviceVersion = request.getVersion();
        if (!StringUtils.isEmpty(serviceVersion)) {
            serviceName += "-" + serviceVersion;
        }

        Object serviceBean = handlerMap.get(serviceName);

        if (serviceBean == null) {
            throw new RuntimeException(String.format("can not find service bean by key: %s", serviceName));
        }
        Class<?> serviceClass = serviceBean.getClass();

        String methodName = request.getMethodName();

        Class<?>[] parameterTypes = request.getParameterTypes();

        Object[] parameters = request.getParameters();

        //反射调用

//        Method method = serviceClass.getMethod(methodName,parameterTypes);
//
//        method.setAccessible(true);
//
//        Object result = method.invoke(serviceBean,parameters);

        //使用 CGLib 执行反射调用
        FastClass serviceFastClass = FastClass.create(serviceClass);

        FastMethod serviceFastMethod = serviceFastClass.getMethod(methodName, parameterTypes);

        return serviceFastMethod.invoke(serviceBean,parameters);
    }
}
